home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_095 / cmd / cmd.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  17KB  |  625 lines

  1.  
  2. /* Cmd.c --- v4 --- Carolyn Scheppner  CBM  07/87
  3.  *
  4.  * Copyright (c) 1987  Commodore Business Machines - All Rights Reserved
  5.  *    This code may be freely non-commercially redistributed.
  6.  *
  7.  * Redirects exec serial or parallel device CMD_WRITEs to a file
  8.  *  (for the purpose of capturing printer output in a file)
  9.  * Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
  10.  *
  11.  * CLI Usage:  [run] cmd [-s] [-m] [-n] devicename filename
  12.  *   -s (Skip) skips any short initial write (usually a Reset if screendump)
  13.  *   -m (Multiple) causes cmd to remain installed for multiple files
  14.  *   -n (Notify) enables helpful progress messages 
  15.  *   devicename serial or parallel
  16.  *
  17.  * WB Usage:  Just doubleclick.
  18.  *            Specify the args in your icon's ToolTypes (use WB Info)
  19.  *            Built-in defaults are:
  20.  *               DEVICE=parallel
  21.  *               FILE=ram:CMD_file
  22.  *               SKIP=FALSE
  23.  *               MULTIPLE=FALSE
  24.  *               NOTIFY=FALSE
  25.  *
  26.  *   Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
  27.  *         The printer device then delays long enough for the reset
  28.  *         to complete, to prevent the loss of subsequent output data.
  29.  *         When the dump is instead captured in a file, this delay
  30.  *         is of course lost.  If your printer driver outputs a reset
  31.  *         at the start of a dump (as ours do), use the -s (SKIP) option
  32.  *         to keep the initial CMD_WRITE out of the file.
  33.  *
  34.  * Sorry about the busywait synchronization of the device wedge
  35.  * and the main process.  The purpose was to avoid unnecessary
  36.  * meddling with the message structures and the device's signals.
  37.  * I had to add a conditional kludge in MyBeginIO to allow Cmd
  38.  * to work with our HPLaser drivers which do PWrites within a Forbid
  39.  * in their Close logic to print/eject last sheet, and also apparently
  40.  * during their open logic if drivers are resident.
  41.  *
  42.  * v2 mods: changes to MyBeginIO for -1 and 0 length CMD_WRITES, usage
  43.  * v3 mods: added buffering of small writes to speed file IO
  44.  * v4 mods: Conditional kludges added to MyBeginIO for HPLaser
  45.  *          (if Forbidden, sneaks the data into main's write buffer)
  46.  *          (EXTRALEN added to wbuf size to allow extra room for this) 
  47.  *          myWrite now doesn't Write if len = 0
  48.  *          MyClose now conditional on writecnt, not reqcnt
  49.  *
  50.  * Linkage info (requires assembler module cmda):
  51.  * Compile with -v on LC2.
  52.  *    FROM    LIB:Astartup.obj, cmd.o, cmda.o
  53.  *    TO      cmd
  54.  *    LIBRARY LIB:Amiga.lib,LIB:LC.lib
  55.  */
  56.  
  57. #include "exec/types.h" 
  58. #include "exec/memory.h" 
  59. #include "exec/io.h"
  60. #include "exec/libraries.h"
  61. #include "exec/execbase.h"
  62. #include "libraries/dos.h" 
  63. #include "libraries/dosextens.h"
  64. #include "workbench/startup.h"
  65. #include "workbench/workbench.h"
  66. #include "devices/serial.h" 
  67. #include "devices/parallel.h" 
  68.  
  69. /* #define DEBUG */
  70.  
  71. #define TOUPPER(c)      ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c)) 
  72. #define HIGHER(x,y)     ((x)>(y)?(x):(y))
  73.  
  74. #define WBUFLEN   2048L
  75. #define EXTRALEN   256L
  76.  
  77. #define INBUFLEN    40L
  78. #define REQSIZE    120L    /* should be big enough or any OpenDevice */
  79.  
  80. #define DEV_CLOSE    LIB_CLOSE
  81. #define DEV_EXPUNGE  LIB_EXPUNGE
  82. /*      DEV_BEGINIO  (-30)       defined in exec/io.h */
  83.  
  84. #define OPEN_SIG   SIGBREAKF_CTRL_E
  85. #define WRITE_SIG  SIGBREAKF_CTRL_F
  86. #define CLOSE_SIG  SIGBREAKF_CTRL_D
  87. #define BREAK_SIG  SIGBREAKF_CTRL_C
  88.  
  89. #define SHORT_WRITE (8L)
  90.  
  91. extern VOID  myBeginIO();  /* The assembler entry */
  92. extern VOID  myClose();    /* The assembler entry */
  93. extern VOID  myExpunge();  /* The assembler routine */
  94.  
  95. extern struct ExecBase  *SysBase;
  96. extern struct MsgPort   *CreatePort(); 
  97. extern struct WBStartup *WBenchMsg;
  98.  
  99. ULONG  RealBeginIO, NewBeginIO;
  100. ULONG  RealClose,   NewClose;
  101. ULONG  RealExpunge, NewExpunge;
  102.  
  103. char *noMem      = "Out of memory\n";
  104. char *portName   = "cas_TMP_CMD_PORT";
  105. char *conSpec    = "CON:20/20/600/40/ CMD v4";
  106.  
  107. char u1[]={"\nCLI Usage: [run] Cmd [-s] [-m] [-n] devicename filename\n"};
  108. char u2[]={"  devicename = serial or parallel\n"};
  109. char u3[]={"  -s = SKIP any short initial write (usually a reset if screendump)\
  110. n"};
  111. char u4[]={"  -m = installed for MULTIPLE files until Break or CTRL_C\n"};
  112. char u5[]={"  -n = enables NOTIFY (helpful progress messages)\n\n"};
  113. char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
  114. char u7[]={"   Cancel installation for multiple files by reclicking\n\n"};
  115. char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
  116. char *morehelp = "Type  cmd ?  for more help\n\n";
  117.  
  118. char *prevTaskName = NULL;
  119. char *outFileName, *deviceName;
  120. char mainTaskName[40];
  121. char wbDev[INBUFLEN], wbFile[INBUFLEN];
  122. char sbuf[120], *wbuf = 0;
  123.  
  124. struct Device *TheDevice;
  125. struct Task   *otherTask, *mainTask;
  126.  
  127. struct IOStdReq *myReq, *ioR;
  128. struct MsgPort  *port; 
  129.  
  130.  
  131. LONG  wLen = 1, outFile = NULL;
  132. ULONG total = 0;
  133. ULONG IconBase = NULL;
  134. BOOL  Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
  135. BOOL  Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
  136. int   reqcnt = 0, writecnt = 0, filecnt = 0; fnLen, wi;
  137.  
  138. char cprt[] =
  139.  "Copyright (c) 1987  Commodore Business Machines  All Rights Reserved";
  140.  
  141. VOID MyBeginIO(ior)
  142. struct IOStdReq *ior;
  143.    {
  144.    BOOL   Forbidden;
  145.    char   *data;
  146.    int    k;
  147.  
  148.    /* The code conditional on Forbidden is needed to work with
  149.     * HPLaser drivers which PWrite during a Forbid in their Close
  150.     * logic to print and eject last sheet, and also apparently
  151.     * during the initial write if drivers are resident.
  152.     */
  153.    Forbidden = (SysBase->TDNestCnt >= 0) ? TRUE : FALSE;
  154.  
  155.    reqcnt += 1;
  156.    if((ior->io_Command == CMD_WRITE)&&(ior->io_Length))
  157.       {
  158.       writecnt += 1;
  159.  
  160.       if(writecnt==1)
  161.          {
  162.          if(!Forbidden)  while(MainBusy);
  163.          MainBusy = TRUE;
  164.          Signal(mainTask,OPEN_SIG);
  165.          if(!Forbidden)   while(MainBusy);
  166.          }
  167.  
  168.       /* If device CMD_WRITE uses length -1, convert to actual length */
  169.       if(ior->io_Length==-1)  ior->io_Length = strlen(ior->io_Data);
  170.  
  171.       if((!Skip)||(writecnt>1)||(ior->io_Length > SHORT_WRITE))
  172.          {
  173.          /* This conditional kludge needed to work with HPLaser
  174.           * drivers which PWrite during a Forbid in their
  175.           * Close logic to print/eject last sheet
  176.           */
  177.          if(Forbidden)
  178.             {
  179.             if(ior->io_Length < (WBUFLEN + EXTRALEN - wi))
  180.                {
  181.                data = (char *)ior->io_Data;
  182.                for(k=0; k<ior->io_Length; k++, wi++)  wbuf[wi]=data[k];
  183.                }
  184.             }
  185.          else
  186.             {
  187.             while(MainBusy);
  188.             MainBusy = TRUE;
  189.             ioR = ior;
  190.             Signal(mainTask,WRITE_SIG);  /* Signal write */
  191.             while(MainBusy);
  192.             }
  193.          }
  194.       ior->io_Actual = ior->io_Length;
  195.       }
  196.    if(!(ior->io_Flags & IOF_QUICK))  ReplyMsg(ior);
  197.    }
  198.  
  199.  
  200. VOID MyClose(ior)
  201. struct IOStdReq *ior;
  202.    {
  203.    /* Note - Exec has us in a forbid here */
  204.    if(writecnt) /* Ignores DOS's initial Open/Close/Open */
  205.       {
  206.       Signal(mainTask,CLOSE_SIG);  /* Signal Close */
  207.       }
  208.    }
  209.  
  210. main(argc, argv) 
  211. UWORD argc; 
  212. TEXT *argv[]; 
  213.    { 
  214.    ULONG signals;
  215.    int k;
  216.  
  217.    FromWb = (argc==0) ? TRUE : FALSE;
  218.  
  219.    if(FromWb)
  220.       {
  221.       getWbArgs(WBenchMsg);
  222.       deviceName  = wbDev;
  223.       outFileName = wbFile;
  224.       }
  225.    else
  226.       {
  227.       if(strEqu(argv[1], "?"))  usageHelpExit();
  228.       if(argc<3) usageExit();
  229.  
  230.       for(k=1; argv[k][0]=='-'; k++)
  231.          {
  232.          if(argv[k][1] == 's')  Skip = TRUE;
  233.          if(argv[k][1] == 'm')  Multiple = TRUE;
  234.          if(argv[k][1] == 'n')  Notify = TRUE;
  235.          }
  236.       if(argc-k < 2)  usageExit();
  237.       deviceName  = argv[k++];
  238.       outFileName = argv[k];
  239.       }
  240.  
  241.    fnLen = strlen(outFileName); /* Used if Multiple extension added */
  242.  
  243.    /* Result will be mainTaskName = "cas_CMD_whatever.device"
  244.     *   with deviceName pointing to the eighth character
  245.     */
  246.    strcpy(&mainTaskName[0],"cas_CMD_");
  247.    strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
  248.    strcpy(&mainTaskName[strlen(mainTaskName)],".device");
  249.    deviceName = &mainTaskName[8];
  250.  
  251.    Forbid();
  252.    if(otherTask = (struct Task *)FindTask(mainTaskName))
  253.       {
  254.       Permit();
  255.       if(FromWb) Signal(otherTask,BREAK_SIG);
  256.       else printf("Device already redirected... exiting\n");
  257.       cleanexit();
  258.       }
  259.  
  260.    mainTask = (struct Task *)FindTask(NULL);
  261.    prevTaskName = mainTask->tc_Node.ln_Name;
  262.    mainTask->tc_Node.ln_Name = mainTaskName;
  263.    Permit();
  264.      
  265.    /* initialize */
  266.    if(!(wbuf = (char *)AllocMem(WBUFLEN+EXTRALEN,MEMF_PUBLIC|MEMF_CLEAR)))
  267.       cleanexit("Can't allocate write buffer\n");
  268.    wi = 0;    /* index into wbuf */
  269.  
  270.    if(!(port = CreatePort(portName, 0)))  cleanexit("Can't open port\n");
  271.  
  272.    myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
  273.    if (!myReq)  cleanexit(noMem);
  274.  
  275.    myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  276.    myReq->io_Message.mn_ReplyPort = port;
  277.  
  278.    if(OpenDevice(deviceName, 0, myReq, 0))
  279.       {
  280.       sprintf(sbuf,"Can't open %s\n",deviceName);
  281.       cleanexit(sbuf);
  282.       }
  283.    TheDevice = myReq->io_Device;
  284.  
  285.    /* Install device IO redirection */
  286.  
  287.    Forbid();
  288.    RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
  289.    RealClose   = SetFunction(TheDevice, DEV_CLOSE,   myClose);
  290.    RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
  291.    Permit();
  292.  
  293.    /* Expunge disabled, CloseDevice so another can open it */
  294.    CloseDevice(myReq);
  295.  
  296.    if(Notify)
  297.       {
  298.       sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
  299.       message(sbuf);
  300.       }
  301.  
  302.    while(!Done)
  303.       {
  304.       signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
  305.  
  306.       if(signals & OPEN_SIG)   /* Open */
  307.          {
  308.          if(!outFile)   /* No output file currently open */
  309.             {
  310.             if(Multiple)  /* If Multiple, add .n extension to filename */
  311.                {
  312.                filecnt++;
  313.                sprintf(&outFileName[fnLen],".%ld",filecnt);
  314.                }
  315.              /* open output file */
  316.             outFile = Open(outFileName, MODE_NEWFILE);
  317.             wLen = 1;
  318.             total = 0;
  319.             /* This moved due to sneak-into-buffer HP kludge */
  320.             /* wi = 0;     Init now at Alloc, and each Close */
  321.             Error1 = TRUE;
  322.  
  323.             if(Notify)
  324.                {
  325.                sprintf(sbuf,"Redirecting %s to %s\n",
  326.                          deviceName,outFileName);
  327.                message(sbuf);
  328.                }
  329.  
  330.             }
  331. #ifdef DEBUG
  332.       printf("Processed OPEN_SIG, file %s, handle $%lx\n",
  333.                  outFileName,outFile);
  334. #endif
  335.          }
  336.  
  337.       if(signals & WRITE_SIG)   /* Write */
  338.          {
  339.          if((outFile)&&(wLen > -1))
  340.             {
  341.             wLen = bufOrWrite(outFile,ioR->io_Data,ioR->io_Length);
  342.             }
  343.          else if(Error1)
  344.             {
  345.             message("Cmd file error: Cancel device output\n");
  346.             Error1 = FALSE;
  347.             }
  348. #ifdef DEBUG
  349.       printf("Processed WRITE_SIG, ioLen %ld, wLen %ld, Error1 = %ld\n",
  350.                  ioR->io_Length, wLen, Error1);
  351. #endif
  352.          }
  353.  
  354.       if(signals & (CLOSE_SIG|BREAK_SIG))
  355.          {
  356.          /* Close file now so user can copy even if something is wrong */
  357.          /* Null the handle - to prevent Write or re-Close */
  358.          if(!Multiple)  signals |= BREAK_SIG;
  359.          if(outFile)
  360.             {
  361.             /* Write buffer contents */
  362.             if((wi>0)&&(wLen>-1)) wLen = myWrite(outFile,wbuf,wi);
  363.             wi = 0;    /* moved from Open logic */
  364.  
  365.             Forbid();
  366.             Close(outFile);
  367.             outFile = NULL;
  368.             writecnt = 0;
  369.             reqcnt = 0;
  370.             Permit();
  371.  
  372.             if((!Multiple)||(Notify))
  373.                {
  374.                sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
  375.                           total,deviceName,outFileName);
  376.                message(sbuf);
  377.                }
  378.             }
  379. #ifdef DEBUG
  380.       printf("Processed CLOSE_SIG, total %ld\n", total);
  381. #endif
  382.          }
  383.  
  384.       if(signals & BREAK_SIG)
  385.          {
  386. #ifdef DEBUG
  387.       printf("Got BREAK_SIG\n");
  388. #endif
  389.          while(!Done)
  390.             {
  391.             /* Wait till we can reopen the device */
  392.             while(OpenDevice(deviceName, 0L, myReq, 0L))  Delay(50L);
  393.  
  394.             /* If it's been re-loaded, we can leave            */
  395.             /* Shouldn't be possible since we disabled Expunge */
  396.             if((ULONG)myReq->io_Device != (ULONG)TheDevice)
  397.                {
  398.                Done = TRUE;
  399.                }
  400.             else
  401.                {
  402.                Forbid();
  403.  
  404.                NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
  405.                NewClose   = SetFunction(TheDevice, DEV_CLOSE,   RealClose);
  406.                NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
  407.  
  408.                if((NewBeginIO != (ULONG)myBeginIO)
  409.                    ||(NewClose != (ULONG)myClose)
  410.                      ||(NewExpunge != (ULONG)myExpunge))
  411.                   {
  412.                   /* Someone else has changed the vectors */
  413.                   /* We put theirs back - can't exit yet  */
  414.                   SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);              
  415.     SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  416.                   SetFunction(TheDevice, DEV_CLOSE,   NewClose);                
  417.   SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  418.                   SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
  419.                   }
  420.                else
  421.                   {
  422.                   Done = TRUE;
  423.                   }
  424.                Permit();
  425.                }
  426.             CloseDevice(myReq);
  427.             if(!Done)  message("Vectors have changed - can't restore\n");
  428.             }
  429.          }
  430.       MainBusy = FALSE;
  431.       }
  432.  
  433.    sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
  434.    cleanexit(sbuf);
  435.    }
  436.  
  437.  
  438. /* Output buffering */
  439.  
  440. bufOrWrite(fh,data,len)
  441. LONG fh;
  442. char *data;
  443. int len;
  444.    {
  445.    int k, wlen;
  446.  
  447.    wlen = len;
  448.  
  449.    /* If possible, just buffer the output data */
  450.    if(len <  WBUFLEN - wi)
  451.       {
  452.       for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  453.       }
  454.    else
  455.       {
  456.       /* Else output any buffered data to the file */
  457.       if(wi>0)  wlen = myWrite(fh,wbuf,wi);
  458.       wi = 0;
  459.  
  460.       /* Then either buffer or write out current request */
  461.       if(wlen > -1)
  462.          {
  463.          if(len < WBUFLEN)
  464.             {
  465.             for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  466.             wlen = len;
  467.             }
  468.          else
  469.             {
  470.             wlen = myWrite(fh,data,len);
  471.             }
  472.          }
  473.       }
  474.    return(wlen);
  475.    }
  476.  
  477.  
  478. /* myWrite also updates total */
  479. myWrite(fh,data,len)
  480. LONG fh;
  481. char *data;
  482. int len;
  483.    {
  484.    int wlen = 0;
  485.  
  486.    if(len)
  487.       {
  488.       wlen = Write(fh,data,len);
  489.       if (wlen > -1) total += wlen;
  490.       }
  491.    return(wlen);
  492.    }
  493.  
  494.  
  495. /* Cleanup and exits */
  496.  
  497. usageHelpExit()
  498.    { 
  499.    int k;
  500.    for(k=0; k<7; k++) printf(us[k]);
  501.    exit(RETURN_OK);
  502.    } 
  503.  
  504. usageExit()
  505.    { 
  506.    printf(u1);
  507.    printf(morehelp);
  508.    exit(RETURN_OK);
  509.    } 
  510.  
  511. cleanexit(s)
  512.    char  *s;
  513.    {
  514.    message(s);
  515.    cleanup();
  516.    exit(RETURN_OK);
  517.    }
  518.  
  519. cleanup()
  520.    {
  521.    if(myReq)   FreeMem(myReq,REQSIZE);
  522.    if(port)    DeletePort(port);
  523.    if(outFile) Close(outFile);
  524.    if(wbuf)    FreeMem(wbuf,WBUFLEN+EXTRALEN);
  525.  
  526.    Forbid();
  527.    if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
  528.    Permit();
  529.    }
  530.  
  531.  
  532. message(s)
  533. char *s;
  534.    {
  535.    LONG con;
  536.  
  537.    if((!FromWb)&&(*s)) printf(s);
  538.    if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
  539.       {
  540.       Write(con,s,strlen(s));
  541.       Delay(120L);
  542.       Close(con);
  543.       }
  544.    }
  545.  
  546.  
  547. getWbArgs(wbMsg)
  548. struct WBStartup *wbMsg;
  549.    {
  550.    struct WBArg  *wbArg;
  551.    struct DiskObject *diskobj;
  552.    char **toolarray;
  553.    char *s;
  554.  
  555.    /* Defaults */
  556.    strcpy(wbDev,"parallel");
  557.    strcpy(wbFile,"ram:CMD_file");
  558.    Skip = FALSE;
  559.    Multiple = FALSE;
  560.    Notify = FALSE;
  561.  
  562.    wbArg = wbMsg->sm_ArgList;
  563.  
  564.    if((IconBase = OpenLibrary("icon.library", 0)))
  565.       {
  566.       diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
  567.       if(diskobj)
  568.          {
  569.          toolarray = (char **)diskobj->do_ToolTypes;
  570.  
  571.          if(s=(char *)FindToolType(toolarray,"DEVICE"))  strcpy(wbDev,s);
  572.          if(s=(char *)FindToolType(toolarray,"FILE"))    strcpy(wbFile,s);
  573.          if(s=(char *)FindToolType(toolarray,"SKIP"))
  574.             {
  575.             if(strEqu(s,"TRUE"))  Skip = TRUE;
  576.             }
  577.          if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
  578.             {
  579.             if(strEqu(s,"TRUE"))  Multiple = TRUE;
  580.             }
  581.          if(s=(char *)FindToolType(toolarray,"NOTIFY"))
  582.             {
  583.             if(strEqu(s,"TRUE"))  Notify = TRUE;
  584.             }
  585.          FreeDiskObject(diskobj);
  586.          }
  587.       CloseLibrary(IconBase);
  588.       }
  589.    }
  590.  
  591.  
  592. /* String functions */
  593.  
  594. strEqu(p, q) 
  595. TEXT *p, *q; 
  596.    { 
  597.    while(TOUPPER(*p) == TOUPPER(*q))
  598.       {
  599.       if (*(p++) == 0)  return(TRUE);
  600.       ++q; 
  601.       }
  602.    return(FALSE);
  603.    } 
  604.  
  605. strlen(s)
  606. char *s;
  607.    {
  608.    int i = 0;
  609.    while(*s++) i++;
  610.    return(i);
  611.    }
  612.  
  613. strcpy(to,from)
  614. char *to, *from;
  615.    {
  616.    do
  617.       {
  618.       *to++ = *from;
  619.       }
  620.    while(*from++);
  621.    }
  622.  
  623. /* end */
  624.  
  625.